package org.theSeed.runner;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBatch;
import org.redisson.api.RLock;
import org.redisson.client.RedisException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.theSeed.base.pojo.constant.SysConstant;
import org.theSeed.base.utils.SeedStringUtil;
import org.theSeed.mapper.SysResourceMapper;
import org.theSeed.mapper.SysRoleMapper;
import org.theSeed.pojo.dto.SysResourceAndRoleCode;
import org.theSeed.pojo.po.SysRole;
import org.theSeed.rbacBaseCommon.pojo.constant.RbacConstant;
import org.theSeed.rbacBaseCommon.pojo.dto.CacheRoleInfoDto;
import org.theSeed.rbacBaseCommon.pojo.sysEnum.ResourceTypeEnum;
import org.theSeed.redisIntegration.utils.RedisUtil;

import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Component
public class RbacFlushRunner implements ApplicationRunner {
    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysResourceMapper sysResourceMapper;

    @Override
    @Transactional
    public void run(ApplicationArguments args){
        RLock lock = RedisUtil.getRedissonClient().getLock(RbacConstant.PERMISSION_UPDATE_PREFIX + SysConstant.SEED);
        if (lock.tryLock()){
            try {
                RBatch batch = RedisUtil.getRedissonClient()
                        .createBatch();

                List<SysRole> sysRoles = sysRoleMapper.selectList(Wrappers.lambdaQuery());
                List<SysResourceAndRoleCode> sysRoleResourceRels = sysResourceMapper.findResourceAndRoleCode();

                sysRoles.stream()
                        .forEach(ele -> {
                            CacheRoleInfoDto cacheRoleInfoDto = new CacheRoleInfoDto();
                            cacheRoleInfoDto.setRoleCode(cacheRoleInfoDto.getRoleCode());
                            cacheRoleInfoDto.setRoleName(cacheRoleInfoDto.getRoleName());
                            cacheRoleInfoDto.setEnableFlag(cacheRoleInfoDto.getEnableFlag());

                            batch.getBucket(RbacConstant.SEED_ROLE_INFO_PREFIX+ele.getRoleCode()).setAsync(cacheRoleInfoDto);
                        });

                sysRoleResourceRels.stream()
                        .collect(Collectors.groupingBy(SysResourceAndRoleCode::getRoleCode,Collectors.toList()))
                        .entrySet().stream().forEach(ele->{
                            String roleResourcePermissionKey = RbacConstant.RESOURCE_PERMISSION_KEY_PREFIX + ele.getKey();
                            String roleApiPermissionKey = RbacConstant.API_PERMISSION_KEY_PREFIX + ele.getKey();

                            HashMap<String, Object> menuMap = new HashMap<>();
                            HashMap<String, Object> permissionMap = new HashMap<>();
                            ele.getValue()
                                    .stream()
                                    .forEach(son->{
                                        if (ObjectUtil.isNotEmpty(son.getResourceCode())){
                                            if (ResourceTypeEnum.isMenu(son.getResourceType())){
                                                menuMap.put(son.getResourceCode(),son.getResourceCode());
                                            }else{
                                                permissionMap.put(SeedStringUtil.concatStr(son.getParentCode(),":",son.getResourceCode()),son.getResourceCode());
                                            }
                                        }
                                    });
                            batch.getKeys().deleteAsync(roleResourcePermissionKey,roleApiPermissionKey);
                            batch.getMap(roleResourcePermissionKey).putAllAsync(menuMap);
                            batch.getMap(roleApiPermissionKey).putAllAsync(permissionMap);
                        });

                batch.execute();
            }finally {
                lock.unlock();
            }
        }else{
            log.warn("字典自启动刷新失败");
        }
    }
}
